package conf

import (
	"os"
	"time"

	"github.com/spf13/viper"
)

type Config struct {
	Base  *baseConf  `mapstructure:"base"`
	Mail  *mailConf  `mapstructure:"mail"`
	Http  *httpConf  `mapstructure:"http"`
	Biz   *bizConf   `mapstructure:"biz"`
	Mq    *mqConf    `mapstructure:"mq"`
	Redis *redisConf `mapstructure:"redis"`
	//Mysql *mysqlConf `mapstructure:"mysql"`
	Pgsql *postgresql `mapstructure:"postgresql"`
	Rpc   *rpcConf    `mapstructure:"rpc"`
	Keys  *keysConf   `json:"keys"`
}

// baseConf is struct of base config
type baseConf struct {
	PidFile        string `mapstructure:"pid_file"`
	Debug          bool   `mapstructure:"debug"`
	MaxProc        int
	BugAccountName string   `mapstructure:"bug_account_name"`
	BugAccount     string   `mapstructure:"bug_account"`
	BugAccountPwd  string   `mapstructure:"bug_account_pwd"`
	BugReportTos   []string `mapstructure:"bug_report_tos"`
	Root           string   `mapstructure:"root"`
}

type mailConf struct {
	Host string `mapstructure:"host"`
	Port string `mapstructure:"port"`
}

// httpConf is config for http server
type httpConf struct {
	Address           string        `mapstructure:"address"`
	ReadTimeout       time.Duration `mapstructure:"read_timeout"`
	WriteTimeout      time.Duration `mapstructure:"write_timeout"`
	ReadHeaderTimeout time.Duration `mapstructure:"read_header_timeout"`
	IdleTimeout       time.Duration `mapstructure:"idle_timeout"`
}

type rpcConf struct {
	Port    string `mapstructure:"rpc_port"`
	GsmsRpc string `mapstructure:"gsms_rpc"`
	OpenRpc string `mapstructure:"open_rpc"`
}

// mysqlConf if config for mysql
//type mysqlConf struct {
//	Address      string        `mapstructure:"address"`
//	User         string        `mapstructure:"user"`
//	Password     string        `mapstructure:"password"`
//	Database     string        `mapstructure:"database"`
//	ReadTimeout  time.Duration `mapstructure:"read_timeout"`
//	WriteTimeout time.Duration `mapstructure:"write_timeout"`
//	IdleTimeout  time.Duration `mapstructure:"idle_timeout"`
//	MaxOpenConns int           `mapstructure:"max_open_conns"`
//	MaxIdleConns int           `mapstructure:"max_idle_conns"`
//	MaxLifeTime  time.Duration `mapstructure:"max_life_time"`
//}

type postgresql struct {
	Host         string        `mapstructure:"host"`
	Port         string        `mapstructure:"port"`
	User         string        `mapstructure:"user"`
	Password     string        `mapstructure:"password"`
	Dbname       string        `mapstructure:"dbname"`
	ReadTimeout  time.Duration `mapstructure:"read_timeout"`
	WriteTimeout time.Duration `mapstructure:"write_timeout"`
	IdleTimeout  time.Duration `mapstructure:"idle_timeout"`
	MaxOpenConns int           `mapstructure:"max_open_conns"`
	MaxIdleConns int           `mapstructure:"max_idle_conns"`
	MaxLifeTime  time.Duration `mapstructure:"max_life_time"`
}

// biz config
type bizConf struct {
	Name           string `mapstructure:"name"`
	MpAppId        string `mapstructure:"mp_app_id"`
	MpRegMsgUrl    string `mapstructure:"mp_reg_msg_url"`
	MpRegMsgPicUrl string `mapstructure:"mp_reg_msg_pic_url"`
}

type keysConf struct {
	PrivKey       string        `mapstructure:"priv_key"`
	PubKey        string        `mapstructure:"pub_key"`
	TokenDuration time.Duration `mapstructure:"token_duration"`
	Secret        string        `mapstructure:"secret"`
}

// nsq config
type mqConf struct {
	NSQLookupds []string `mapstructure:"nsq_lookupds"` // nsq 集群地址
	NSQDAddress string   `mapstructure:"nsqd_address"` // nsqd 地址
}

// redisConf is struct of redis config
type redisConf struct {
	Password    string        `mapstructure:"password"`
	Address     string        `mapstructure:"address"`
	DefaultDB   int           `mapstructure:"default_db"`
	MaxRetries  int           `mapstructure:"max_retries"`
	IdleTimeout time.Duration `mapstructure:"idle_timeout"`
}

func Init(cfgFile string) (*Config, error) {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		viper.AddConfigPath(".")
		viper.SetConfigName("ldaccount")
		viper.SetConfigType("toml")
	}

	if err := viper.ReadInConfig(); err != nil {
		return nil, err
	}
	cfg := NewConfig()
	if err := viper.Unmarshal(cfg); err != nil {
		return nil, err
	}
	// root path
	root, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	cfg.Base.Root = root
	// nsq 优先从环境变量获取
	if os.Getenv("NSQD_ADDRESS") != "" {
		cfg.Mq.NSQDAddress = os.Getenv("NSQD_ADDRESS")
	}
	return cfg, nil
}

func NewConfig() *Config {
	return &Config{
		Base: &baseConf{
			PidFile: "/tmp/ldaccount.pid",
			MaxProc: 0,
		},
		Mail: &mailConf{
			Host: "",
			Port: "",
		},
		Http: &httpConf{
			Address:           "0.0.0.0:8518",
			ReadTimeout:       120 * time.Second,
			WriteTimeout:      120 * time.Second,
			ReadHeaderTimeout: 10 * time.Second,
			IdleTimeout:       10 * time.Second,
		},
		Biz: &bizConf{
			Name:    "平台名称",
			MpAppId: "",
		},
		Keys: &keysConf{
			PrivKey:       "",
			PubKey:        "",
			TokenDuration: 7 * 24 * time.Hour,
			Secret:        "",
		},
		Mq: &mqConf{
			NSQLookupds: nil,
			NSQDAddress: "",
		},
		Redis: &redisConf{
			Password:    "",
			Address:     "",
			DefaultDB:   0,
			MaxRetries:  3,
			IdleTimeout: 5 * time.Second,
		},
		Pgsql: &postgresql{
			Host:         "",
			User:         "",
			Password:     "",
			Dbname:       "",
			ReadTimeout:  60 * time.Second,
			WriteTimeout: 60 * time.Second,
			IdleTimeout:  0,
			MaxOpenConns: 6,
			MaxIdleConns: 2,
			MaxLifeTime:  10 * time.Minute,
		},
		Rpc: &rpcConf{
			Port: "",
		},
	}
}
